package activity

import android.content.Intent
import android.os.Bundle
import android.view.MotionEvent
import android.view.View
import android.widget.Button
import android.widget.EditText
import android.widget.ScrollView
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.hontech.pizzav2.R
import event.AckEvent
import event.BusyChangedEvent
import event.RowHeightChangedEvent
import event.StatusChangedEvent
import event.motor.*
import manager.*
import mvc.model.Status
import org.angmarch.views.NiceSpinner
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import java.text.SimpleDateFormat
import java.util.*
import kotlin.collections.ArrayList

class SettingActivity : AppCompatActivity() {
    companion object {
        var isShow = false
    }

    private val mSpinnerCol: NiceSpinner by lazy {
        findViewById<NiceSpinner>(R.id.id_debug_spinner_col)
    }
    private val mSpinnerRow: NiceSpinner by lazy {
        findViewById<NiceSpinner>(R.id.id_debug_spinner_row)
    }
    private val mSpinner1: NiceSpinner by lazy {
        findViewById<NiceSpinner>(R.id.id_debug_spinner_1)
    }
    private val mSpinner2: NiceSpinner by lazy {
        findViewById<NiceSpinner>(R.id.id_debug_spinner_2)
    }
    private val mSpinner3: NiceSpinner by lazy {
        findViewById<NiceSpinner>(R.id.id_debug_spinner_3)
    }
    private val mSpinner4: NiceSpinner by lazy {
        findViewById<NiceSpinner>(R.id.id_debug_spinner_4)
    }
    private val mTextMessage: TextView by lazy {
        findViewById<TextView>(R.id.id_debug_text_view_display_message)
    }
    private val mScrollView: ScrollView by lazy {
        findViewById<ScrollView>(R.id.id_debug_scroll_view)
    }
    private val mEditTextFridgeValue: EditText by lazy {
        findViewById<EditText>(R.id.id_debug_warehouse_temp)
    }
    private val mEditTextOvenValue: EditText by lazy {
        findViewById<EditText>(R.id.id_debug_oven_temp)
    }
    private val mButtonScan: Button by lazy { findViewById<Button>(R.id.id_debug_warehouse_scan) }
    private val mButtonReset: Button by lazy { findViewById<Button>(R.id.id_debug_initialization) }
    private val mButtonHeatTest: Button by lazy {
        findViewById<Button>(R.id.id_debug_microwave_heating_test)
    }
    private val mEditTextWave: EditText by lazy {
        findViewById<EditText>(R.id.id_debug_microwave_heating_time)
    }
    private val mEditTextHeat: EditText by lazy {
        findViewById<EditText>(R.id.id_debug_infrared_heating_time)
    }
    private val mButtonPickOpen: Button by lazy {
        findViewById<Button>(R.id.id_debug_pick_up_door_open)
    }
    private val mButtonPickClose: Button by lazy {
        findViewById<Button>(R.id.id_debug_pick_up_door_close)
    }
    private val mButtonHeatOpen: Button by lazy {
        findViewById<Button>(R.id.id_debug_security_door_open)
    }
    private val mButtonHeatClose: Button by lazy {
        findViewById<Button>(R.id.id_debug_security_door_close)
    }
    private val mButtonExternPushForward: Button by lazy {
        findViewById<Button>(R.id.id_debug_outer_push_goods_forward)
    }
    private val mButtonExternPushRetreat: Button by lazy {
        findViewById<Button>(R.id.id_debug_outer_push_goods_retreat)
    }
    private val mButtonInnerPushForward: Button by lazy {
        findViewById<Button>(R.id.id_debug_inner_push_goods_forward)
    }
    private val mButtonInnerPushRetreat: Button by lazy {
        findViewById<Button>(R.id.id_debug_inner_push_goods_retreat)
    }
    private val mButtonExternUpDownOpen: Button by lazy {
        findViewById<Button>(R.id.id_debug_external_lift_rise)
    }
    private val mButtonExternUpDownClose: Button by lazy {
        findViewById<Button>(R.id.id_debug_external_lift_decline)
    }
    private val mEditWaveTime: EditText by lazy {
        findViewById<EditText>(R.id.id_debug_edit_heating_time1)
    }
    private val mEditInfrTime: EditText by lazy {
        findViewById<EditText>(R.id.id_debug_edit_heating_time0)
    }
    private val mEditHeatValue: EditText by lazy {
        findViewById<EditText>(R.id.id_debug_edit_heating_temp)
    }
    private val mButtonDelivery: Button by lazy {
        findViewById<Button>(R.id.id_debug_single_cargo_shipments)
    }
    private val mButtonSave: Button by lazy { findViewById<Button>(R.id.id_debug_button_save) }
    private val mButtonExit: Button by lazy {
        findViewById<Button>(R.id.id_debug_button_exit_debug)
    }
    private val mButtonExitApp: Button by lazy { findViewById<Button>(R.id.id_debug_exit_app) }
    private val mButtonQuery: Button by lazy { findViewById<Button>(R.id.id_debug_status_query) }
    private val mButtonSingleCol: Button by lazy {
        findViewById<Button>(R.id.id_debug_entire_column_shipments)
    }
    private val mButtonDeliveryAll: Button by lazy {
        findViewById<Button>(R.id.id_debug_all_cargo_shipments)
    }
    private val mButtonPause: Button by lazy { findViewById<Button>(R.id.id_debug_shipments_pause) }
    private val mButtonResume: Button by lazy {
        findViewById<Button>(R.id.id_debug_shipments_resume)
    }

    private val mLists = ArrayList<ColumnAndRow>()
    private var mColManager = SingleColumnDelegate(mLists, ::onDeliveryComplete)
    private var mAllManager = AllDeliveryDelegate(mLists, ::onDeliveryComplete)
    private var type = 0x00 //  00 col 01 all

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_set)
        initUi()
    }

    private fun initUi() {

        val rowHeight = resources.getStringArray(R.array.cargo_row_col_arg)
        val cols = resources.getStringArray(R.array.shipment_col_array)
        val rows = resources.getStringArray(R.array.shipment_row_array)
        mSpinnerCol.attachDataSource(cols.toMutableList())
        mSpinnerRow.attachDataSource(rows.toMutableList())
        mSpinner1.attachDataSource(rowHeight.toMutableList())
        mSpinner2.attachDataSource(rowHeight.toMutableList())
        mSpinner3.attachDataSource(rowHeight.toMutableList())
        mSpinner4.attachDataSource(rowHeight.toMutableList())
/*        mSpinnerRow.setSelectedTextFormatter(null)
        mSpinnerCol.setSelectedTextFormatter(null)
        mSpinner1.setSelectedTextFormatter(null)
        mSpinner2.setSelectedTextFormatter(null)
        mSpinner3.setSelectedTextFormatter(null)
        mSpinner4.setSelectedTextFormatter(null)*/

        mButtonScan.setOnClickListener {
            mLists.clear()
            DeliveryManager.scan()
        }

        mButtonReset.setOnClickListener(DeliveryManager::reset)
        mButtonHeatTest.setOnClickListener(::onClickHeat)
        mButtonPickOpen.setOnClickListener(DeliveryManager::pickOpen)
        mButtonPickClose.setOnClickListener(DeliveryManager::pickClose)
        mButtonHeatClose.setOnClickListener(DeliveryManager::heatClose)
        mButtonHeatOpen.setOnClickListener(DeliveryManager::heatOpen)
        mButtonExternPushForward.setOnClickListener(DeliveryManager::externPushForward)
        mButtonExternPushRetreat.setOnClickListener(DeliveryManager::externPushRetreat)
        mButtonInnerPushForward.setOnClickListener(DeliveryManager::innerPushForward)
        mButtonInnerPushRetreat.setOnClickListener(DeliveryManager::innerPushRetret)
        mButtonExternUpDownClose.setOnClickListener(DeliveryManager::externUpDownClose)
        mButtonExternUpDownOpen.setOnClickListener(DeliveryManager::externUpDownOpen)
        mButtonDelivery.setOnClickListener(::onClickDeliverySingle)
        mButtonSave.setOnClickListener(::onClickSave)
        mButtonExit.setOnClickListener(::onClickExit)
        mButtonExitApp.setOnClickListener(::onClickExitApp)
        mButtonQuery.setOnClickListener(::onClickQueryStatus)
        mButtonSingleCol.setOnClickListener(::onClickColDelivery)
        mButtonPause.setOnClickListener(::onClickPause)
        mButtonResume.setOnClickListener(::onClickResume)
        mButtonDeliveryAll.setOnClickListener(::onClickAllDelivery)
    }

    private fun onClickExit(view: View) {
        finish()
    }

    private fun onClickExitApp(view: View) {
        val i = Intent(this, MainActivity::class.java)
        i.putExtra(MainActivity.QUIT_ACTION, true)
        startActivity(i)
    }

    private fun onDeliveryComplete(type: Int) {
        if (type == 0x00) {
            appendMessage("Entire column test complete")
        } else if (type == 0x01) {
            appendMessage("All units test complete")
        }
    }

    /**
     * 单列出货
     */
    private fun onClickColDelivery(view: View) {
        if (mLists.isEmpty()) {
            appendMessage("Please scan the inventory first")
            return
        }
        val wave = mEditWaveTime.text
        if (wave.isEmpty()) {
            appendMessage("Please enter the microwave heating time")
            return
        }
        val infr = mEditInfrTime.text
        if (infr.isEmpty()) {
            appendMessage("Please enter the infrared heating time")
            return
        }
        val temp = mEditHeatValue.text
        if (temp.isEmpty()) {
            appendMessage("Please enter the heating temperature")
            return
        }
        val col = mSpinnerCol.selectedIndex
        if (col < 1) {
            appendMessage("Please select the shipments column")
            return
        }
        var t = ((temp.toString().toInt() - 32) / 1.8f).toInt()
        if (t < 0) {
            t = 0
        }
        mAllManager.pause = true
        mColManager.waveTime = wave.toString().toInt()
        mColManager.infrTime = infr.toString().toInt()
        mColManager.tempValue = t
        mColManager.start(col)
        type = 0x00
    }

    private fun onClickPause(view: View) // 出货暂停
    {
        mAllManager.pause = true
        mColManager.pause = true
    }

    private fun onClickResume(view: View) // 出货继续
    {
        if (type == 0x00) {
            mAllManager.pause = true
            mColManager.pause = false
            mColManager.complete()
        } else if (type == 0x01) {
            mColManager.pause = true
            mAllManager.pause = false
            mAllManager.complete()
        }
    }

    /**
     * 全部出货
     */
    private fun onClickAllDelivery(view: View) {
        if (mLists.isEmpty()) {
            appendMessage("Please scan the inventory first")
            return
        }
        val wave = mEditWaveTime.text
        if (wave.isEmpty()) {
            appendMessage("Please enter the microwave heating time")
            return
        }
        val infr = mEditInfrTime.text
        if (infr.isEmpty()) {
            appendMessage("Please enter the infrared heating time")
            return
        }
        val temp = mEditHeatValue.text
        if (temp.isEmpty()) {
            appendMessage("Please enter the heating temperature")
            return
        }
        var t = ((temp.toString().toInt() - 32) / 1.8f).toInt()
        if (t < 0) {
            t = 0
        }
        mColManager.pause = true
        mAllManager.waveTime = wave.toString().toInt()
        mAllManager.infrTime = infr.toString().toInt()
        mAllManager.tempValue = t
        mAllManager.start()
        type = 0x01
    }

    private fun onClickSave(view: View) {
        val col1 = mSpinner1.selectedIndex
        if (col1 < 1) {
            appendMessage("Please select the first column")
            return
        }
        val col2 = mSpinner2.selectedIndex
        if (col2 < 1) {
            appendMessage("Please select the second column")
            return
        }
        val col3 = mSpinner3.selectedIndex
        if (col3 < 1) {
            appendMessage("Please select the third column")
            return
        }
        val col4 = mSpinner4.selectedIndex
        if (col4 < 1) {
            appendMessage("Please select the fourth column")
            return
        }
        DeliveryManager.setRows(col1 - 1, col2 - 1, col3 - 1, col4 - 1)
    }

    /**
     * 单个出货
     */
    private fun onClickDeliverySingle(view: View) {
        val wave = mEditWaveTime.text
        if (wave.isEmpty()) {
            appendMessage("Please enter the microwave heating time")
            return
        }
        val infr = mEditInfrTime.text
        if (infr.isEmpty()) {
            appendMessage("Please enter the infrared heating time")
            return
        }
        val temp = mEditHeatValue.text
        if (temp.isEmpty()) {
            appendMessage("Please enter the heating temperature")
            return
        }
        val row = mSpinnerRow.selectedIndex
        if (row < 1) {
            appendMessage("Please select the shipments row")
            return
        }
        val col = mSpinnerCol.selectedIndex
        if (col < 1) {
            appendMessage("Please select the shipments column")
            return
        }
        var t = ((temp.toString().toInt() - 32) / 1.8f).toInt()
        if (t < 0) {
            t = 0
        }
        mAllManager.pause = true
        mColManager.pause = true
        DeliveryManager.delivery(
            col,
            row,
            wave.toString().toInt(),
            infr.toString().toInt(),
            t,
            0
        ) {
            if (it != null) {
                onAckEvent(it)
            }
        }
    }

    private fun onClickHeat(view: View) {
        val wave = mEditTextWave.text
        if (wave.isEmpty()) {
            appendMessage("Please enter the microwave heating time")
            return
        }
        val heat = mEditTextHeat.text
        if (heat.isEmpty()) {
            appendMessage("Please enter the infrared heating time")
            return
        }
        DeliveryManager.heat(wave.toString().toInt(), heat.toString().toInt())
    }

    private fun onClickQueryStatus(view: View) {
        val status = StatusManager.status
        appendMessageWithStatus(status)
    }

    private fun clearMsgIf() {
        if (mTextMessage.text.length > 1024 * 1024) {
            mTextMessage.text = ""
        }
    }

    private fun appendMessage(msg: String) {
        clearMsgIf()
        val format = SimpleDateFormat.getTimeInstance()
        val s = format.format(Calendar.getInstance().time)
        mTextMessage.append("$s:$msg\r\n")
        mScrollView.fullScroll(ScrollView.FOCUS_DOWN)
    }

    private fun appendMessageWithStatus(status: Status) {
        clearMsgIf()
        val format = SimpleDateFormat.getTimeInstance()
        val s = format.format(Calendar.getInstance().time)
        mTextMessage.append("$s:\r\n${status.queryStatus()}")
        mScrollView.fullScroll(ScrollView.FOCUS_DOWN)
    }

    @Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
    fun onDeliveryStatusChangedEvent(env: DeliveryChangedEvent) {
        val sb = StringBuilder()
        sb.append("${env.col}-${env.row}:${env.status()}")
        appendMessage(sb.toString())

        if (env.state == DeliveryChangedEvent.Complete) {
            mAllManager.complete()
            mColManager.complete()
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
    fun onInitChangedEvent(env: InitChangedEvent) {
        val arr = resources.getStringArray(R.array.return_value)
        appendMessage(arr[env.state])
    }

    @Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
    fun onExternPushChangedEvent(env: ExternPushChangedEvent) {
        if (env.state == MotorCode.OK) {
            if (env.status == ExternPushChangedEvent.STATUS_FORWARD) {
                appendMessage("The elect goods oven is forward")
            } else {
                appendMessage("The elect goods oven is retreat")
            }
            return
        }
        val arr = resources.getStringArray(R.array.return_value)
        val msg = arr[env.state]
        appendMessage(msg)
    }

    @Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
    fun onPickDoorChangedEvent(env: PickDoorChangedEvent) {
        if (env.state == MotorCode.OK) {
            if (env.status == PickDoorChangedEvent.STATUS_CLOSE) {
                appendMessage("The delivery door is close")
            } else {
                appendMessage("The delivery door is open")
            }
        }
        val arr = resources.getStringArray(R.array.return_value)
        val msg = arr[env.state]
        appendMessage(msg)
    }

    @Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
    fun onPushMotorChangedEvent(env: PushMotorChangedEvent) {
        if (env.state == MotorCode.OK) {
            if (env.status == PushMotorChangedEvent.STATUS_LEFT) {
                appendMessage("The eject goods fridge is retreat")
            } else {
                appendMessage("The eject goods fridge is forward")
            }
            return
        }
        val arr = resources.getStringArray(R.array.return_value)
        val msg = arr[env.state]
        appendMessage(msg)
    }

    @Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
    fun onHeatDoorChangedEvent(env: HeatDoorChangedEvent) {
        if (env.state == MotorCode.OK) {
            if (env.status == HeatDoorChangedEvent.STATUS_CLOSE) {
                appendMessage("The fridge/oven door is close")
            } else {
                appendMessage("The fridge/oven door is open")
            }
            return
        }
        val arr = resources.getStringArray(R.array.return_value)
        val msg = arr[env.state]
        appendMessage(msg)
    }

    @Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
    fun onExternUpDownChangedEvent(env: ExternUpDownChangedEvent) {
        if (env.state == MotorCode.OK) {
            if (env.status == ExternUpDownChangedEvent.STATUS_DOWN) {
                appendMessage("The oven is close")
            } else {
                appendMessage("The oven is open")
            }
            return
        }
        val arr = resources.getStringArray(R.array.return_value)
        val msg = arr[env.state]
        appendMessage(msg)
    }

    @Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
    fun onScanStatusChangedEvent(env: ScanStatusChangedEvent) {
        val row = env.row
        val col = env.col
        if (env.state == MotorCode.OK) {
            val code = env.barCode()
            appendMessage("$col-$row:Barcode:$code")
            mLists.add(ColumnAndRow(col, row))
            return
        } else if (env.state == MotorCode.SCAN_FINISH) {
            appendMessage("Bar code scanning is complete")
            return
        } else {
            AppTask.postDelayed({
                onClickQueryStatus(mButtonQuery)
            }, 1000)
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
    fun onRowHeightChangedEvent(env: RowHeightChangedEvent) {
        val row1 = env.row1
        val row2 = env.row2
        val row3 = env.row3
        val row4 = env.row4

        try {
            mSpinner1.selectedIndex = DeliveryManager.indexWithRowHeight(row1)
            mSpinner2.selectedIndex = DeliveryManager.indexWithRowHeight(row2)
            mSpinner3.selectedIndex = DeliveryManager.indexWithRowHeight(row3)
            mSpinner4.selectedIndex = DeliveryManager.indexWithRowHeight(row4)
            DeliveryManager.rows1 = DeliveryManager.rowsWithHeight(row1)
            DeliveryManager.rows2 = DeliveryManager.rowsWithHeight(row2)
            DeliveryManager.rows3 = DeliveryManager.rowsWithHeight(row3)
            DeliveryManager.rows4 = DeliveryManager.rowsWithHeight(row4)
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
    fun onStatusChangedEvent(env: StatusChangedEvent) {

        if (MY_LOCATION == LOCATION_US) {
            val fridge = String.format("%.1f℉", env.status.fridgeTempValue() * 1.8f + 32)
            val oven = String.format("%.1f℉", env.status.ovenTempValue * 1.8f + 32)
            mEditTextFridgeValue.setText(fridge)
            mEditTextOvenValue.setText(oven)
        } else if (MY_LOCATION == LOCATION_UK) {
            val fridge = String.format("%.1f℃", env.status.fridgeTempValue())
            val oven = String.format("%d℃", env.status.ovenTempValue)
            mEditTextFridgeValue.setText(fridge)
            mEditTextOvenValue.setText(oven)
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
    fun onRowHeightSettingChangedEvent(env: RowHeightSettingChangedEvent) {
        val arr = resources.getStringArray(R.array.return_value)
        val msg = when (env.state) {
            in MotorCode.range -> arr[env.state]
            else -> "Unknown error"
        }
        appendMessage("Save:$msg")
    }

    @Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
    fun onAckEvent(env: AckEvent) {
        AppTask.post {
            when (env.status) {
                AckEvent.OK -> {
                    appendMessage("Wait...")
                }

                AckEvent.BUSY -> {
                    appendMessage("Busy...")
                }

                else -> {
                    appendMessage("Abnormal communication")
                }
            }
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
    fun onBusyStatusChanged(env: BusyChangedEvent) {

    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        if (event.action == MotionEvent.ACTION_DOWN) {
            if (currentFocus != null && currentFocus!!.windowToken != null) {
                AppManager.imm.hideSoftInputFromWindow(window.decorView.windowToken, 0)
            }
        }
        return super.onTouchEvent(event)
    }

    override fun onStart() {
        super.onStart()
        isShow = true
        AppManager.isBusy = true
        EventBus.getDefault().register(this)
        DeliveryManager.queryRowHeight()
    }

    override fun onStop() {
        super.onStop()
        isShow = false
        AppManager.isBusy = false
        EventBus.getDefault().unregister(this)
    }
}

private class AllDeliveryDelegate(
    val list: ArrayList<ColumnAndRow>,
    val onComplete: (Int) -> Unit
) {
    var waveTime = 0
    var infrTime = 0
    var tempValue = 0
    var pause = false

    fun complete() {
        if (pause) {
            return
        }
        if (!list.isEmpty()) {
            list.removeAt(0)
        }
        if (list.isEmpty()) {
            onComplete(0x01)
            return
        }
        next()
    }

    fun next() {
        try {
            val info = list.first()
            DeliveryManager.delivery(
                info.col,
                info.row,
                waveTime,
                infrTime,
                tempValue,
                0, {

                }
            )
        } catch (e: Exception) {
            e.printStackTrace()
            onComplete(0x01)
        }
    }

    fun start() {
        pause = false
        next()
    }
}

/**
 * 单列出货的委托
 */
private class SingleColumnDelegate(
    val list: ArrayList<ColumnAndRow>,
    val onComplete: (Int) -> Unit
) {
    var waveTime = 0
    var infrTime = 0
    var tempValue = 0
    var pause = false
    var col = 0x01
    var row = 0x01

    fun complete() // 出货成功
    {
        if (pause) {
            return
        }
        list.remove(ColumnAndRow(col, row)) // 移除已经出货过的
        row += 0x01
        if (row > DeliveryManager.rowsWithCol(col)) {
            onComplete(0x00)
            return
        }
        next()
    }

    fun next() // 出货下一个
    {
        for (info in list) {
            if (info.col == col) {
                row = info.row
                DeliveryManager.delivery(
                    col,
                    row,
                    waveTime,
                    infrTime,
                    tempValue,
                    0, {

                    }
                )
                return
            }
        }
        onComplete(0x00)
    }

    fun start(col: Int) {
        pause = false
        this.col = col
        next()
    }

}

private class ColumnAndRow(val col: Int, val row: Int) {
    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (other !is ColumnAndRow) return false

        if (col != other.col) return false
        if (row != other.row) return false

        return true
    }

    override fun hashCode(): Int {
        var result = col
        result = 31 * result + row
        return result
    }
}

